package com.heima.search.service.impl;

import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dto.UserSearchDto;
import com.heima.model.search.pojo.ApAssociateWords;
import com.heima.search.model.Trie;
import com.heima.search.service.ApAssociateWordsService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.lang.ref.SoftReference;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by ZYJ on 2021/6/9 0:00
 */
@Service
public class ApAssociateWordsServiceImpl implements ApAssociateWordsService, InitializingBean {
    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 搜索联想词API
     * @param userSearchDto
     * @return
     */
    @Override
    public ResponseResult findAssociate(UserSearchDto userSearchDto) {
        if(userSearchDto.getSearchWords() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2 执行查询 模糊查询
        List<ApAssociateWords> associateWordList = mongoTemplate.find(Query.query(
                Criteria.where("associateWords")
                        .regex(".*" + userSearchDto.getSearchWords() + ".*"))
                            , ApAssociateWords.class);

        return ResponseResult.okResult(associateWordList);
    }
    //如果放到方法中随着方法执行完毕就会被jvm回收
    //如果内存紧张 需要释放这个资源时   new 属于强引用 不会被回收  软引用 弱引用
    public static SoftReference<Trie> softReference;
    /**
     * 搜索联想词API  用Trie优化搜索联想词
     * @param userSearchDto
     * @return
     */
    @Override
    public ResponseResult findAssociateV2(UserSearchDto userSearchDto) {
        //当项目启动时初始化 Trie树
        Trie trie = softReference.get();
        if(trie == null){
            //有可能被回收 可以重新初始化下
            initTrieData();
        }
        //查询联想词 从Trie树中获取联想词
        List<String> dataList = trie.getData(userSearchDto.getSearchWords());
        //封装apassociatewords 返回
        List<ApAssociateWords> apAssociateWords = dataList.stream().map(str -> {
            ApAssociateWords associateWords = new ApAssociateWords();
            associateWords.setAssociateWords(str);
            return associateWords;
        }).collect(Collectors.toList());
        return ResponseResult.okResult(apAssociateWords);
    }

    //初始化树的方法,项目只要已启动就要调它
    public void initTrieData(){
        //查询所有联想词放到trie树中
        List<ApAssociateWords> all = mongoTemplate.findAll(ApAssociateWords.class);
        Trie trie = new Trie();
        all.stream().map(ApAssociateWords::getAssociateWords).forEach(trie::insert);

        softReference = new SoftReference<Trie>(trie);
    }
//实现InitializingBean 当前Spring实例执行完毕后,执行的初始化方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("=========初始化方法============");
        initTrieData();
    }


}
